#pragma once

#include "../common/net.hpp"
#include "../common/message.hpp"
#include<set>
namespace RPC_project
{
    namespace server
    {
        class ProviderMannager
        {
        public:
            using ptr = std::shared_ptr<ProviderMannager>;

            struct Provider
            {
                using ptr = std::shared_ptr<Provider>;
                Provider(const BaseConnection::ptr &conn , const Address &host)
                    :_conn(conn) ,_host(host)
                {}

                void appendMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _methods.push_back(method);
                }

                std::mutex _mutex;
                BaseConnection::ptr _conn;
                Address _host;
                std::vector<std::string> _methods;
            };
            
            //新服务provider进行服务注册时进行调用 
            void addProvider(const BaseConnection::ptr &conn , const Address &host ,const std::string &method)
            {
                Provider::ptr provider;
                {
                    //查找_conns中有没有此服务提供者对象 ，有就获取 ，没有就创建并建立关联(conn 与Provider:;ptr的关联)
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it= _conns.find(conn);
                    if(it != _conns.end())
                    {
                        provider = it->second;
                    }
                    else
                    {
                    
                        provider = std::make_shared<Provider>(conn ,host);
                        _conns.insert(std::make_pair(conn , provider));
                    }
                    //method提供者中主机中加一
                    auto &providers =_providers[method];
                    providers.insert(provider);

                }
                //向服务对象中新增一个所能提供的服务名称
                provider->appendMethod(method);

            }

            //provider断开链接时获取它的信息 ，用于提供服务下线的通知(向discover服务发现者进行通知)
            Provider::ptr getProvider(const BaseConnection::ptr &conn)
            {
                
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it= _conns.find(conn);
                    if(it != _conns.end())
                    {
                        return it->second;
                    }
                    return Provider::ptr();
            }

            //provider链接断开 ，删除provider的信息
            void deletProvidor(const BaseConnection::ptr &conn )
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it= _conns.find(conn);
                    if(it == _conns.end())
                    {
                        //当前断开的不是服务提供者
                        return;
                    }
                    //当前断开的是服务提供者
                    for(auto & method : it->second->_methods)
                    {
                        auto & providers =_providers[method];
                        providers.erase(it->second);
                    }
                    //删除连接与服务提供者的关联关系
                    _conns.erase(it);
            }
            std::vector<Address> methodHosts(const std::string& method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _providers.find(method);
                if(it == _providers.end())
                {
                    ELOG("现在还没有人提供 %s 服务" , method.c_str());
                }
                std::vector<Address> result;
                for(auto &provider: it->second)
                {
                    result.push_back(provider->_host);
                }

                return result;
            }

        private:
            std::mutex _mutex;
            //<"Add" ,set[host1, host2 , ...]>
            std::unordered_map<std::string , std::set<Provider::ptr>> _providers;
            //将连接和服务提供者一一对应 
            //服务提供者下线后可通过conn 找到ptr，向服务的发现者通知其下线了
            std::unordered_map<BaseConnection::ptr , Provider::ptr> _conns;

        };


        class DiscoverMannager
        {
            public:
            using ptr = std::shared_ptr<DiscoverMannager>;

            struct Discover
            {
                using ptr = std::shared_ptr<Discover>;
                Discover(const BaseConnection::ptr & conn)
                    :_conn(conn)
                {}
                void appendMethod(const std::string & method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _methods.push_back(method);
                }
                
                std::mutex _mutex;
                BaseConnection::ptr  _conn;//发现者的客户端连接
                //发现过的服务名称
                std::vector<std::string> _methods;
            };

            //客户端进行服务发现时 ，新增服务发现者，新增服务名称
            Discover::ptr addDiscoverer(const BaseConnection::ptr & conn , const std::string & method)
            {
                Discover::ptr discoverer;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(conn);
                    if(it == _conns.end())
                    {
                        //没找到
                        discoverer = std::make_shared<Discover>(conn);
                        _conns.insert(std::make_pair(conn ,discoverer));

                    }
                    else
                    {
                        discoverer =it->second;
                    }
                    auto & discoverers =_discoverers[method];//用引用
                    discoverers.insert(discoverer);
                }
                discoverer->appendMethod(method);
                return discoverer;
            }
            //发现者客户端下线，从std::unordered_map<std::string , std::vector<Discover>> _providers中删除
            void deletDiscover(const BaseConnection::ptr & conn)
            {
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(conn);
                    if(it == _conns.end())
                    {
                    //没有找到连接对应的发现者信息，代表客户端不是一个服务发现者
                        return ;
                    }
                    else
                    {
                        for(auto &method : it->second->_methods)
                        {
                            auto & discoverers =_discoverers[method];
                            discoverers.erase(it->second);
                        }
                    }
                    _conns.erase(it);
                }
            }
            //新的服务提供者上线 ，进行上线通知
            void onlineNotify(const std::string &method ,const Address &host)
            {
                return notify(method,host,ServiceOptype::SERVICE_ONLINE);

            }
            //服务提供者下线 ，进行下线通知
            void offlineNotify(const std::string &method ,const Address &host)
            {
                return notify(method,host,ServiceOptype::SERVICE_OFFLINE);
            }

            private:
                void notify(const std::string &method ,const Address &host ,ServiceOptype optype)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it =_discoverers.find(method);
                    if(it == _discoverers.end())
                    {
                        //这代表这个服务当前没有发现者
                        return;
                    }
                    //服务上线或者下线的请求
                    auto base_req = MessageFactory::Create(MType::REQ_SERVICE);
                    RPC_project::ServiceRequest::ptr msg_req= std::dynamic_pointer_cast<RPC_project::ServiceRequest>(base_req);
                        msg_req->Setid(UUID::uuid());
                        msg_req->SetMyType(MType::REQ_SERVICE);
                        msg_req->SetMethod(method);
                        msg_req->SetHost(host);
                        msg_req->SetOpType(optype);
                    for(auto &discover: it->second )
                    {
                        discover->_conn->Send(msg_req);
                    }
                }

            private:
            std::mutex _mutex;
            std::unordered_map<std::string , std::set<Discover::ptr>> _discoverers;//这个服务被哪些主机 发现过
            //发现者下线后，找到发现者的信息 ，从std::unordered_map<std::string , std::vector<Discover>>中删除其信息
            std::unordered_map<BaseConnection::ptr , Discover::ptr> _conns;

        };


        //对外
        class ProviderAndDiscover
        {
            public:
                using ptr = std::shared_ptr<ProviderAndDiscover>;
                ProviderAndDiscover()
                :_providers(std::make_shared<ProviderMannager>())
                ,_discoverers(std::make_shared<DiscoverMannager>())
                {}


                //根据不同的服务(发现request或者注册request)进行处理的回调函数 。会提交给dispatcher
                //接受servicerequest 返回serviceresponse
                void onServiceRequest(const BaseConnection::ptr &conn ,const ServiceRequest::ptr &msg)
                {
                    ServiceOptype optype = msg->OpType();
                
                    if(optype == ServiceOptype::SERVICE_REGISTRY)
                    {
                        ILOG("%s :%d 进行服务注册 %s" , msg->Host().first.c_str(), msg->Host().second ,msg->Method().c_str());
                        //服务注册：
                        //1.新增服务提供者  2.进行服务上线的通知
                        _providers->addProvider(conn, msg->Host() ,msg->Method());
                        _discoverers->onlineNotify(msg->Method() ,msg->Host());
                        //向客户端 发送response
                        
                        return registryResponse(conn ,msg);
                    }
                    else if(optype == ServiceOptype::SERVICE_DISCOVERY)
                    {
                        ILOG("客户端进行服务发现 %s" ,msg->Method().c_str());
                        //服务发现：
                        //新增服务发现者
                        _discoverers->addDiscoverer(conn , msg->Method());

                        //向客户端 发送response
                        return discoveryResponse(conn ,msg);
                    }
                    else{
                        ELOG("收到服务操作请求 ，但是服务操作类型错误");
                        return errorResponse(conn ,msg);
                    }
                }

                //连接断开时，判断是服务提供者连接断开 ，还是服务发现者连接断开
                void onConnectionShutdown(const BaseConnection::ptr &conn)
                {
                    auto provider = _providers->getProvider(conn);
                    if(provider != nullptr)//provide.get()?
                    {
                        ILOG("%s:%d 服务下线 " , provider->_host.first.c_str(), provider->_host.second );
                        for(auto &method: provider->_methods)
                        {  //下线通知
                            _discoverers->offlineNotify(method ,provider->_host);

                        }
                        _providers->deletProvidor(conn);
                    }
                    _discoverers->deletDiscover(conn);
                }
            private:
                void registryResponse(const BaseConnection::ptr &conn ,const ServiceRequest::ptr &msg )
                {
                    auto base_rsp =MessageFactory::Create(MType::RSP_SERVICE);
                    RPC_project::ServiceResponse::ptr msg_rsp= std::dynamic_pointer_cast<RPC_project::ServiceResponse>(base_rsp);
                    msg_rsp->Setid(msg->Rid());
                    msg_rsp->SetRcode(RCode::RCODE_OK);
                    msg_rsp->SetMyType(MType::RSP_SERVICE);
                    msg_rsp->SetOpType(ServiceOptype::SERVICE_REGISTRY);
                    conn->Send(msg_rsp);
                }
                void discoveryResponse(const BaseConnection::ptr &conn ,const ServiceRequest::ptr &msg )
                {
                    auto base_rsp =MessageFactory::Create(MType::RSP_SERVICE);
                    RPC_project::ServiceResponse::ptr msg_rsp= std::dynamic_pointer_cast<RPC_project::ServiceResponse>(base_rsp);
                    msg_rsp->Setid(msg->Rid());
                    msg_rsp->SetMyType(MType::RSP_SERVICE);
                    msg_rsp->SetOpType(ServiceOptype::SERVICE_DISCOVERY);
                    std::vector<Address> hosts =_providers->methodHosts(msg->Method());
                    if(hosts.empty())
                    {
                        msg_rsp->SetRcode(RCode::RCODE_NOT_FOUND_SERVICE);
                        return conn->Send(msg_rsp);//一定要return 就不会向下运行
                    }

                    msg_rsp->SetRcode(RCode::RCODE_OK);
                    msg_rsp->SerMethod(msg->Method());
                    msg_rsp->SetHost(hosts);
                    return conn->Send(msg_rsp);
                }
                void errorResponse(const BaseConnection::ptr &conn ,const ServiceRequest::ptr &msg)
                {
                    auto base_rsp =MessageFactory::Create(MType::RSP_SERVICE);
                    RPC_project::ServiceResponse::ptr msg_rsp= std::dynamic_pointer_cast<RPC_project::ServiceResponse>(base_rsp);
                    msg_rsp->Setid(msg->Rid());
                    msg_rsp->SetMyType(MType::RSP_SERVICE);
                    msg_rsp->SetOpType(ServiceOptype::SERVICE_UNKNOW);
                    msg_rsp->SetRcode(RCode::RCODE_INVALID_OPTYPE);
                    conn->Send(msg_rsp);

                }
            private:
                ProviderMannager::ptr _providers;
                DiscoverMannager::ptr _discoverers;
        };
    }
}